package org.cedar.syntaxcore;
import java.util.Date;
import java.util.List;

import org.cedar.exceptions.CalcException;
import org.cedar.exceptions.VariantIOException;



public class MetaElement {
        public int valueType;
        public Object value;
        public Object params;
        private SyntaxContext ctx;
        public int getValueType() {
            if (this.valueType == VariantType.vtVariant) {
                try {
					return this.getValueType(ctx.get((String)this.value,
					                                  (List)this.params));
				} catch (VariantIOException e) {
					return VariantType.vtUnknow;
				}
            }
            return this.valueType;
        }

        public MetaElement(Object element) {
            this.valueType = this.getValueType(element);
            this.value = element;
        }

        public MetaElement(Object element, Object params,SyntaxContext ctx) {
            this.valueType = VariantType.vtVariant;
            this.params = params;
            this.value = element;
            this.ctx = ctx;
        }

        private int getValueType(Object element) {
            int valueType = VariantType.vtUnknow;
            if (element instanceof String)
                valueType = VariantType.vtString;
            else if (element instanceof Integer)
                valueType = VariantType.vtInt;
            else if (element instanceof Double)
                valueType = VariantType.vtDouble;
            else if (element instanceof Long)
            	valueType = VariantType.vtLong;
            else if (element instanceof java.util.Date)
                valueType = VariantType.vtDateTime;
            else if (element instanceof Boolean)
                valueType = VariantType.vtBool;
            else
                valueType = VariantType.vtUnknow;
            return valueType;
        }

        public String toString(int valueType, Object value) {
            switch (valueType) {
            case VariantType.vtUnknow:
                return "";
            case VariantType.vtBool:
            case VariantType.vtInt:
            case VariantType.vtDouble:
            case VariantType.vtLong:
            case VariantType.vtString:
                return value.toString();
            case VariantType.vtDateTime:
                return Consts.simpleDateFormat.format((java.util.Date) value);
//            case VariantType.vtVariant:
//                Object v = ctx.getValue((String)value,(List)this.params);
//                return null == v? "": v.toString();
            default:
                return "";
            }
        }

        public String toString() {
            if (this.valueType == VariantType.vtVariant) {
                Object v = null;
                try {
					v = ctx.get((String)this.value, (List)this.params);
				} catch (VariantIOException e) {
					System.err.println(e);
				}
                return toString(getValueType(v), v);
            }
            return toString(this.valueType, value);
        }
        public Object value(){
        	Object v = null;
        	if (this.valueType == VariantType.vtVariant) {
				v = ctx.get((String)this.value, (List)this.params);
            }else
            	v =  this.value;
        	return v;
        }
        public boolean getAsBoolean(int objType, Object obj) throws
                CalcException {
            if (null == obj)
                throw new CalcException(3001);
            switch (objType) {
            case VariantType.vtBool:
                return ((Boolean) obj).booleanValue();
            case VariantType.vtInt:
                return ((Integer) obj).intValue() > 0;
            case VariantType.vtDouble:
                return ((Double) obj).intValue() > 0;
            case VariantType.vtLong:
            	return ((Long) obj).longValue() > 0L;
            case VariantType.vtString:
             	return new Boolean((String)value);
            default:
                throw new CalcException(3002,
                                        VariantType.getVariantTypeTitle(objType));
            }
        }

        public boolean getAsBoolean() throws CalcException {
            if (this.valueType == VariantType.vtVariant) {
                Object v = ctx.get((String)this.value, (List)this.params);
                return this.getAsBoolean(this.getValueType(v), v);
            }
            return this.getAsBoolean(this.valueType, this.value);
        }

        public int getAsInt(int valueType, Object value) throws CalcException {
            if (null == value)
                throw new CalcException(3003);
            switch (valueType) {
            case VariantType.vtInt:
                return ((Integer) value).intValue();
            case VariantType.vtDouble:
                return ((Double) value).intValue();
            case VariantType.vtLong:
            	return ((Long) value).intValue();
            case VariantType.vtString:
             	return new Integer((String)value);
            default:
                throw new CalcException(3004, 
                                        VariantType.
                                        getVariantTypeTitle(valueType));
            }
        }

        public int getAsInt() throws CalcException {
            if (this.valueType == VariantType.vtVariant) {
                Object obj = ctx.get((String)this.value, (List)this.params);
                return this.getAsInt(this.getValueType(obj), obj);
            }
            return this.getAsInt(this.valueType, this.value);
        }

        public double getAsDouble() throws CalcException {
            if (this.valueType == VariantType.vtVariant) {
                Object obj = ctx.get((String)this.value, (List)this.params);
                return this.getAsDouble(this.getValueType(obj), obj);
            }
            return this.getAsDouble(this.valueType, this.value);
        }
        public long getAsLong() throws CalcException {
        	if (this.valueType == VariantType.vtVariant) {
        		Object obj = ctx.get((String)this.value, (List)this.params);
        		return this.getAsLong(this.getValueType(obj), obj);
        	}
        	return this.getAsLong(this.valueType, this.value);
        }

        public long getAsLong(int valueType, Object value) throws CalcException{
        	 switch (valueType) {
             case VariantType.vtInt:
                 return ((Integer) value).longValue();
             case VariantType.vtDouble:
                 return ((Double) value).longValue();
             case VariantType.vtLong:
             	return ((Long) value).longValue();
             case VariantType.vtString:
             	return new Long((String)value);
             default:
                 throw new CalcException(3005,
                                         VariantType.
                                         getVariantTypeTitle(valueType));
             }
        }
        public double getAsDouble(int valueType, Object value) throws
                CalcException {
            switch (valueType) {
            case VariantType.vtInt:
                return ((Integer) value).doubleValue();
            case VariantType.vtDouble:
                return ((Double) value).doubleValue();
            case VariantType.vtLong:
            	return ((Long) value).doubleValue();
            case VariantType.vtString:
            	return new Double((String)value);
            default:
                throw new CalcException(3006,
                                        VariantType.
                                        getVariantTypeTitle(valueType));
            }
        }

        public Date getAsDateTime() throws CalcException {
            if (this.valueType == VariantType.vtVariant) {
                Object obj = ctx.get((String)this.value, (List)this.params);
                return this.getAsDateTime(this.getValueType(obj), obj);
            }
            return this.getAsDateTime(this.valueType, this.value);
        }

        public Date getAsDateTime(int valueType, Object value) throws
                CalcException {
            switch (valueType) {
            case VariantType.vtDateTime:
                return (java.util.Date) value;
            default:
                throw new CalcException(3007,
                                        VariantType.getVariantTypeTitle(
                        valueType));
            }
        }

        public String getAsString() throws CalcException {
            return this.toString();
        }

        public boolean equals(Object o) {
            boolean ret = o != null &&
                          this.getClass().getName().equalsIgnoreCase(o.getClass().
                    getName());
            ret = ret && this.toString().equals(o.toString());
            return ret;
        }
    }
